from typing import List, Self, Literal

from game.sprites.player.player import Player
from game.sprites.sprites import SpritesContainer, GroupsContainer
from game.sprites.base import Entity
from game.container import Variables
from game.world.coordinate import Coordinate


class Area: ...

class World:
    _instance = None
    
    def __init__(self):
        self.areas = []
        
        # Create player object
        self.player = SpritesContainer.PLAYER.player
        
        self.__class__._instance = self
        
    @classmethod
    def load(cls) -> None:
        """ Load world from saves """
        raise NotImplementedError
    
    @classmethod
    def save(cls) -> None:
        """ Save world to saves """
        raise NotImplementedError
    
    @classmethod
    def getWorld(cls) -> Self:
        if cls._instance is None:
            raise Exception("World is not initialized")
        
        return cls._instance
                
    def getPlayer(self) -> Player:
        return self.player
        
    def getAllEntity(self) -> List[Entity]:
        return GroupsContainer.visible_group.sprites()
    
    def getAllEntityWithoutPlayer(self) -> List[Entity]:
        entity = self.getAllEntity()
        entity.remove(self.player)
        
        rst = []
        
        for e in entity:
            if not e.is_barrier: rst.append(e)
        
        return rst
    
    def getEntityAroundPlayer(self, radius: float, sort: Literal["nearest", "farthest"] | None = None) -> List[Entity]:
        if sort is None:
            ret = []
            for entity in self.getAllEntityWithoutPlayer():
                if entity.is_barrier: continue
                distance = self.player.getDistance(entity.coordinate) # type: ignore
                if distance > radius: continue               
                ret.append(entity)
            
            return ret
                
        dis = {}
        for entity in self.getAllEntityWithoutPlayer():
            if entity.is_barrier: continue
            distance = self.player.getDistance(entity.coordinate) # type: ignore
            if distance > radius: continue               
            dis[distance] = entity
            
        sorted_dis = sorted(dis.items(), key=lambda x: x[0], reverse = (sort == "farthest"))
                
        return [item for _, item in sorted_dis]